package stocket

import (
	"encoding/json"
	"fmt"
	"game/entity"
	socketio_client "github.com/zhouhui8915/go-socket.io-client"
	"log"
	"math/rand"
	"time"
)

const (
	URL                            = "http://8.148.244.147:13000"
	GAME_URL                       = "http://8.148.244.147:15172"
	CLIENT_CREATION_INTERVAL_IN_MS = 10
	ENTER_GAME_FLAG                = true
	CURR_POWER_VAL                 = 9000
	ROOM_ID                        = 1
	SCENE_ID                       = 1
)

type Account struct {
	ID       int    `json:"id"`
	UserName string `json:"userName"`
	DeviceID string `json:"device_id"`
}

var (
	accounts = []Account{
		{ID: 48165, UserName: "robot_5eGY3WUQj", DeviceID: "jpajv8jjrp0sg"},
	}

	MAX_CLIENTS      int
	clientCount      int
	handleIDs        []int
	endID            int
	users            = make(map[int]entity.UserInfo)
	clientSockets    = make(map[int]*socketio_client.Client)
	gameSockets      = make(map[int]*socketio_client.Client)
	freeCountRecords = make(map[int]int)
	loginState       = make(map[int]int)
	startID          = 1001
	runningUsers     = make(map[int]int)
	outUsers         = make(map[int]int)
	reconnectUser    []int
	freeUsers        []int
	runoutUsers      []int
	timestampEmit    time.Time
)

func init() {
	rand.Seed(time.Now().UnixNano())
	if len(accounts) >= 100 {
		MAX_CLIENTS = 100
	} else {
		MAX_CLIENTS = len(accounts)
	}
	fmt.Println(MAX_CLIENTS)
}

func CreateUserInfo() {
	if clientCount >= len(accounts) {
		return
	}

	sex := rand.Intn(2)

	userInfo := entity.UserInfo{
		LocalID:    startID,
		UID:        accounts[clientCount].ID,
		UserName:   accounts[clientCount].UserName,
		Password:   "123123==",
		HeadImgURL: "",
		NickName:   accounts[clientCount].UserName,
		Sex:        sex,
		Province:   "广东省",
		City:       "广州市",
		Country:    "荔湾区",
		DeviceID:   accounts[clientCount].DeviceID,
	}

	users[userInfo.LocalID] = userInfo

	fmt.Printf("create user info: %d\n", startID)
	createClient(userInfo.LocalID)

	startID++
}

func createClient(userID int) {
	opts := &socketio_client.Options{
		Transport: "websocket",
		Query:     make(map[string]string),
	}

	client, err := socketio_client.NewClient(URL, opts)
	if err != nil {
		log.Printf("Error creating client: %v\n", err)
		return
	}

	client.On("loginResult", func(data interface{}) {
		defer func() {
			if r := recover(); r != nil {
				log.Printf("Error processing loginResult: %v\n", r)
			}
		}()

		result, ok := data.(map[string]interface{})
		if !ok {
			log.Printf("Invalid loginResult data format: %v\n", data)
			return
		}

		jsonData, _ := json.Marshal(result)
		log.Printf("test====loginResult: %s\n", jsonData)

		resultID, ok := result["resultid"].(float64)
		if !ok {
			log.Printf("Invalid resultid format: %v\n", result["resultid"])
			return
		}

		if resultID == -3 {
			log.Println(result["msg"])
			return
		} else if resultID == -2 {
			log.Println(result["msg"])
			return
		}

		obj, ok := result["Obj"].(map[string]interface{})
		if ok && obj["id"] != nil {
			if user, exists := users[userID]; exists {
				user.LoginResult = obj
				users[userID] = user

				if ENTER_GAME_FLAG {
					createGameClient(users[userID].LocalID)
				} else {
					return
				}
			} else {
				log.Printf("User not found: %d\n", userID)
			}
		} else {
			log.Printf("User registration failed: %v\n", data)
		}
	})

	client.On("disconnect", func(reason string) {
		log.Printf("disconnect due to %s\n", reason)
		if _, ok := runningUsers[userID]; ok {
			outUsers[userID] = runningUsers[userID]
			delete(runningUsers, userID)
		}
	})

	client.On("connect", func() {
		if _, ok := loginState[userID]; ok {
			if user, exists := users[userID]; exists {
				log.Printf("Reconnection case, directly delete and disconnect: %d\n", user.UID)
			}
		} else {
			user, exists := users[userID]

			if exists {
				time.AfterFunc(time.Duration(rand.Intn(1000)+100)*time.Millisecond, func() {
					client.Emit("login", user)
				})
				clientSockets[userID] = client
				loginState[userID] = 1
			}
		}
	})

	if user, exists := users[userID]; exists {
		handleIDs = append(handleIDs, user.UID)
	}
	clientCount++

	if clientCount < MAX_CLIENTS {
		time.AfterFunc(CLIENT_CREATION_INTERVAL_IN_MS*time.Millisecond, CreateUserInfo)
	} else {
		if user, exists := users[userID]; exists {
			endID = user.UID
		}
	}
}

func createGameClient(userID int) {
	// 创建WebSocket dialer
	opts := &socketio_client.Options{
		Transport: "websocket",
		Query:     map[string]string{"EIO": "3"},
	}

	client, err := socketio_client.NewClient(GAME_URL, opts)
	if err != nil {
		log.Printf("Error creating game client: %v\n", err)
		return
	}

	client.On("loginGameResult", func(data interface{}) {
		jsonData, _ := json.Marshal(data)
		log.Printf("test===== 15172_loginGameResult: %s\n", jsonData)
	})

	client.On("disconnect", func(reason string) {
		log.Printf("game socket disconnect due to %s\n", reason)
		if _, ok := runningUsers[userID]; ok {
			outUsers[userID] = runningUsers[userID]
			delete(runningUsers, userID)
		}
	})

	client.On("connect", func() {
		user, exists := users[userID]

		if exists {
			log.Printf("%s gameSocket connect\n", user.UserName)

			time.AfterFunc(time.Duration(rand.Intn(1000))*time.Millisecond, func() {
				if user, exists := users[userID]; exists && user.LoginResult != nil {
					loginResult := user.LoginResult
					loginData := map[string]interface{}{
						"userid":   loginResult["id"],
						"gametype": nil,
						"sign":     loginResult["sign"],
					}
					jsonData, _ := json.Marshal(loginData)
					client.Emit("LoginGame", string(jsonData))
				} else {
				}
			})
			gameSockets[userID] = client
		}
	})

	client.On("loginGameResult", func(data interface{}) {
		jsonData, _ := json.Marshal(data)
		log.Printf("test==== 15172_loginGameResult: %s\n", jsonData)

		startLottery(userID)

		if _, ok := runningUsers[userID]; ok {
			if user, exists := users[userID]; exists {
				reconnectUser = append(reconnectUser, user.UID)
			}
		} else {
			if user, exists := users[userID]; exists {
				runningUsers[userID] = user.UID
			}
		}
	})

	client.On("lotteryResult", func(data interface{}) {
		result, ok := data.(map[string]interface{})
		if !ok {
			log.Printf("Invalid lotteryResult data format: %v\n", data)
			return
		}

		resultCode, ok := result["ResultCode"].(float64)
		if !ok {
			log.Printf("Invalid ResultCode format: %v\n", result["ResultCode"])
			return
		}

		if resultCode == -1 {
			log.Println("lottery error code -1")
		} else if resultCode == -2 {
			log.Println("lottery error code -2")

			if brokenSubNum, ok := result["BrokenSubNum"].(float64); ok && brokenSubNum >= 0 {
				if _, ok := runningUsers[userID]; ok {
					outUsers[userID] = runningUsers[userID]
					delete(runningUsers, userID)
				}

				if user, exists := users[userID]; exists {
					log.Printf("Insufficient energy, name: %s\n", user.UserName)
					runoutUsers = append(runoutUsers, user.UID)
				}
			}
		}
		isRunout := false
		for _, id := range runoutUsers {
			if id == userID {
				isRunout = true
				break
			}
		}

		if !isRunout {
			if resultData, ok := result["ResultData"].(map[string]interface{}); ok {
				if viewArray, ok := resultData["viewarray"].(map[string]interface{}); ok {
					if user, exists := users[userID]; exists {
						log.Printf("%s====test ====== App result: %v\n", user.UserName, viewArray["nHandCards"])
					}
					time.AfterFunc(time.Duration(rand.Intn(1500)+500)*time.Millisecond, func() {
						startLottery(userID)
					})
				}
			}
		}
	})
}

func startLottery(localID int) {
	if count, ok := freeCountRecords[localID]; ok && count > 0 {
		log.Println("Free attack in progress========================1111")
		return
	}
	client, ok := gameSockets[localID]

	if ok {
		lotteryData := map[string]interface{}{
			"bet":      0,
			"nBetList": []int{CURR_POWER_VAL},
			"roomId":   ROOM_ID,
			"sceneId":  SCENE_ID,
		}
		jsonData, _ := json.Marshal(lotteryData)
		client.Emit("lottery", string(jsonData))

		timestampEmit = time.Now()
		time.AfterFunc(80*time.Second, func() {
			if time.Since(timestampEmit) > 60*time.Second {
				panic("finish 100 users test")
			}
		})
	} else {
		log.Println("Socket status is incorrect")
		log.Println(gameSockets[localID])
	}
}

func StartLogInfo() {
	ticker := time.NewTicker(10 * time.Second)
	defer ticker.Stop()

	for range ticker.C {
		num := len(runningUsers)
		fmt.Printf("Number of people in progress: %d || People in progress: %v\n", num, runningUsers)
		fmt.Println("Free attack record personnel:", freeUsers)
		fmt.Println("Processed IDs:", handleIDs)
		fmt.Println("End ID:", endID)
		fmt.Println("Energy exhausted records:", runoutUsers)
	}
}
